#ifndef MESH_H
#define MESH_H

namespace A48 {


class Mesh {
  PatchContainer  pc_;   // patches
  FaceContainer   fc_;   // faces
  EdgeContainer   ec_;   // edges
  VertexContainer vc_;   // vertices

 public:
  Mesh();
  ~Mesh();

  void delete_patches();

  VertexIter verts_begin(){ return vc_.begin(); };
  VertexIter verts_end(){ return vc_.end(); };
  int num_verts() { return vc_.size(); };

  EdgeIter edges_begin() { return ec_.begin(); };
  EdgeIter edges_end() { return ec_.end(); };
  int num_edges() { return ec_.size(); };

  FaceIter faces_begin() { return fc_.begin(); };
  FaceIter faces_end() { return fc_.end(); };
  int num_faces() { return fc_.size(); };

  PatchIter patches_begin() { return pc_.begin(); };
  PatchIter patches_end() { return pc_.end(); };
  int num_patches() { return pc_.size(); };

  void read_ply(char *fname);
  void read_ply_patches(char *fname);

 private:
  Vertex *add_vertex();
  bool add_vertex(Vertex *v) 
    { std::pair<VertexIter, bool> r = vc_.insert(v); return r.second; };
  void del_vertex(Vertex* v) { vc_.erase(v); delete(v); };

  Hedge *add_edge(Vertex *v0, Vertex *v1);
  bool add_edge(Edge *e) 
    { std::pair<EdgeIter, bool> r = ec_.insert(e);  return r.second;};
  void del_edge(Edge* e) { ec_.erase(e); delete(e); }

  Face* add_face(Hedge* e0, Hedge* e1, Hedge* e2);
  Face* add_face(Hedge *e0, Hedge *e1, Hedge *e2, float v0, float v1, float v2, float v3, float v4, float v5);

  bool add_face(Face* f) 
    { std::pair<FaceIter, bool> r = fc_.insert(f); return r.second;};
  void del_face(Face* f) {
	  Patch *p = f->patch();

	  if (p != NULL)
	  {
		  p->del_face_patch(f);
	  }

	  fc_.erase(f); 
	  delete(f); 
  }

  Patch* add_patch();
  Patch* add_patch(int *i, int size, FaceMap* faces, int camera_index, float *box);
  bool add_patch(Patch* p) 
    { std::pair<PatchIter, bool> r = pc_.insert(p); return r.second;};
  void del_patch(Patch* p) {
	  for (FaceIter fiter = fc_.begin(); fiter != fc_.end(); fiter++)
	  {
		  Face *f = (*fiter);

		  if (f->patch() == p)
		  {
			  f->set_patch(NULL);
		  }
	  }
	  pc_.erase(p);
	  delete(p);
  }

  void link_mesh();

  Hedge* get_hedge(int i0, int i1, Vertex* verts[], HedgeMap* edges);

 public:
  void put_vertex(Vertex *v) { add_vertex(v); };
  void put_face(int i0, int i1, int i2, Vertex* verts[], HedgeMap* edges);
  void put_face(int i0, int i1, int i2, float v0, float v1, float v2, float v3, float v4, float v5, Vertex* verts[], HedgeMap* hedges);
  void put_face(int i0, int i1, int i2, Vertex* verts[], HedgeMap* edges, FaceMap* faces);
  void put_face(int i0, int i1, int i2, float v0, float v1, float v2, float v3, float v4, float v5, Vertex* verts[], HedgeMap* hedges, FaceMap* faces);

  void put_patch();
  void put_patch(int *i, int size, FaceMap* faces, int camera_index, float *box);

  void remove_patch(Patch *p);
};


}

#endif
